﻿using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Interfaces.ViewModels;
using MugenMvvmToolkit.Interfaces.Views;
using MugenMvvmToolkit.Ioc;
using MugenMvvmToolkit.Models;
using MugenMvvmToolkit.ViewModels;

namespace MugenMvvmToolkit.Infrastructure
{
    /// <summary>
    ///     Represents the class that is used to initialize the IOC adapter for unit tests.
    /// </summary>
    public class UnitTestInitializationStrategyExt : UnitTestInitializationStrategy
    {
        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="UnitTestInitializationStrategyExt" /> class.
        /// </summary>
        public UnitTestInitializationStrategyExt()
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="UnitTestInitializationStrategyExt" /> class.
        /// </summary>
        public UnitTestInitializationStrategyExt([NotNull]Func<IInitializationContext, bool> canInitializeViewDelegate, [NotNull] Func<IViewModel, string, IView> getViewDelegate)
            : base(canInitializeViewDelegate, getViewDelegate)
        {
        }

        #endregion

        #region Overrides of UnitTestInitializationStrategy

        /// <summary>
        ///     Initializes the specified <see cref="IIocAdapter" />.
        /// </summary>
        public override void Initialize(IIocAdapter iocAdapter)
        {
            base.Initialize(iocAdapter);
            IocAdapter.BindToBindingInfo(GetEntityStateProvider);
            IocAdapter.BindToBindingInfo(GetValidationProvider);
            IocAdapter.BindToBindingInfo(GetValidatorProvider);
            if (!IocAdapter.CanResolve(typeof (IValidatorProvider))) return;
            var validatorProvider = IocAdapter.Get<IValidatorProvider>();
            foreach (IValidator validator in GetValidators())
            {
                validatorProvider.Register(validator);
            }
        }

#if !NOANNOTATIONVALIDATION
        /// <summary>
        /// Gets the <see cref="IDisplayNameProvider"/> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IDisplayNameProvider"/>.</returns>
        protected override BindingInfo<IDisplayNameProvider> GetDisplayNameProvider()
        {
            if (IocAdapter.CanResolve(typeof(IDisplayNameProvider)))
                return BindingInfo<IDisplayNameProvider>.Empty;
            return BindingInfo<IDisplayNameProvider>.FromInstance(new AnnotationDisplayNameProvider());
        }
#endif

        /// <summary>
        ///     Gets the <see cref="IValidationProvider" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IValidationProvider" />.</returns>
        protected virtual BindingInfo<IValidationProvider> GetValidationProvider()
        {
            if (IocAdapter.CanResolve(typeof (IValidationProvider)))
                return BindingInfo<IValidationProvider>.Empty;
#if !NOANNOTATIONVALIDATION            
            return BindingInfo<IValidationProvider>.FromInstance(new DataAnnotationValidationProvider(IocAdapter.Get<IDisplayNameProvider>(), IocAdapter));
#else
            return BindingInfo<IValidationProvider>.Empty;
#endif
        }

        /// <summary>
        ///     Gets validators.
        /// </summary>
        /// <returns>A series of instances of <see cref="IValidator" />.</returns>
        protected virtual IList<IValidator> GetValidators()
        {
#if !NOANNOTATIONVALIDATION
            return new IValidator[] { new ValidationProviderValidator(), new ValidatableViewModelValidator() };
#else
            return new IValidator[] {new ValidatableViewModelValidator()};
#endif
        }

        /// <summary>
        ///     Gets the <see cref="IEntityStateProvider" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IEntityStateProvider" />.</returns>
        protected virtual BindingInfo<IEntityStateProvider> GetEntityStateProvider()
        {
            if (IocAdapter.CanResolve(typeof (IEntityStateProvider)))
                return BindingInfo<IEntityStateProvider>.Empty;
            return
                BindingInfo<IEntityStateProvider>.FromType<EntityStateProvider>(
                    DependencyLifecycle.TransientScopeInstance);
        }

        /// <summary>
        ///     Gets the <see cref="IValidatorProvider" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IValidatorProvider" />.</returns>
        protected virtual BindingInfo<IValidatorProvider> GetValidatorProvider()
        {
            if (IocAdapter.CanResolve(typeof (IValidatorProvider)))
                return BindingInfo<IValidatorProvider>.Empty;
            return BindingInfo<IValidatorProvider>.FromInstance(new ValidatorProvider(IocAdapter));
        }

        #endregion
    }
}